package user

import (
	"context"
	"strconv"
	"time"

	commonSdk "github.com/wangzhe1991/grpc-sdk/pb/common"
	userSdk "github.com/wangzhe1991/grpc-sdk/pb/user"
	"github.com/xormplus/xorm"

	"gitee.com/krio/grpc-go-server/cmd/lib"
	"gitee.com/krio/grpc-go-server/dao/model"
	"gitee.com/krio/grpc-go-server/dao/model/common"
	user2 "gitee.com/krio/grpc-go-server/dao/model/user"
	"gitee.com/krio/grpc-go-server/tool"
)

type UserDao struct{}

func (u *UserDao) Add(ctx context.Context, req *userSdk.UserCreateReq) (*userSdk.UserCreateResp, error) {
	sfid, err := tool.GetSFID()
	if err != nil {
		return nil, err
	}
	// 登录相关
	userLogin := &user2.UserLogin{
		PhoneNumber:   req.PhoneNumber,
		Email:         req.Email,
		PhoneAreaCode: req.PhoneAreaCode,
		Password:      req.Password,
		SFID: &common.SFID{
			SFID: sfid,
		},
	}
	_, err = lib.X.Table(model.TableUserLogin).Insert(userLogin)
	if err != nil {
		return nil, err
	}
	// 基础信息
	userInfo := &user2.UserInfo{
		UserId:    userLogin.AutoincrID.ID,
		Gender:    (*commonSdk.Gender)(&req.Gender),
		FirstName: req.FirstName,
		LastName:  req.LastName,
		Birthday:  req.Birthday,
	}
	userEdu := &user2.UserEducation{
		UserId: userLogin.AutoincrID.ID,
	}
	_, err = lib.X.Insert(userInfo, userEdu)
	if err != nil {
		return nil, err
	}

	return &userSdk.UserCreateResp{
		Id:   userLogin.AutoincrID.ID,
		Sfid: strconv.FormatInt(userLogin.SFID.SFID, 10),
	}, nil
}

func (u *UserDao) List(ctx context.Context, req *userSdk.UserListReq) (*userSdk.UserListResp, error) {
	type temp struct {
		user2.UserLogin     `xorm:"extends"`
		user2.UserInfo      `xorm:"extends"`
		user2.UserEducation `xorm:"extends"`
	}
	var (
		total int64
		res   []*temp
		data  []*userSdk.UserListResp_One
		err   error
	)
	query := func() *xorm.Session {
		query := lib.X.Table(model.TableUserLogin).Alias("t1").
			Join("INNER", []string{model.TableUserInfo, "t2"}, "t1.id = t2.user_id").
			Join("INNER", []string{model.TableUserEducation, "t3"}, "t1.id = t3.user_id").
			Where("t1.deleted_ts = ?", common.ISDEL_FALSE).
			OrderBy("t1.id DESC")
		return query
	}
	sql := query()
	total, err = query().Count()
	if err != nil {
		return nil, err
	}
	if !req.IsAll {
		sql = sql.Limit(int(req.PageSize), int(req.PageSize*(req.PageIndex-1)))
	}
	err = sql.Find(&res)
	if err != nil {
		return nil, err
	}

	for _, v := range res {
		data = append(data, &userSdk.UserListResp_One{
			Id:                v.UserLogin.ID,
			Sfid:              strconv.FormatInt(v.UserLogin.SFID.SFID, 10),
			PhoneNumber:       v.UserLogin.PhoneNumber,
			PhoneAreaCode:     v.UserLogin.PhoneAreaCode,
			Email:             v.UserLogin.Email,
			FirstName:         v.UserInfo.FirstName,
			LastName:          v.UserInfo.LastName,
			CurrentUniversity: v.UserEducation.CurrentUniversity,
		})
	}

	return &userSdk.UserListResp{
		Data:  data,
		Total: total,
	}, nil
}

func (u *UserDao) Delete(ctx context.Context, UserID int32) (*commonSdk.EmptyResponse, error) {
	cut := &user2.UserLogin{
		DeletedTS: int32(time.Now().Local().Unix()),
	}
	_, err := lib.X.Table(model.TableUserLogin).ID(UserID).Update(cut)
	if err != nil {
		return &commonSdk.EmptyResponse{}, err
	}

	return &commonSdk.EmptyResponse{}, nil
}

func (u *UserDao) Detail(ctx context.Context, userID int32) (*userSdk.UserDetailResp, bool, error) {
	type temp struct {
		user2.UserLogin     `xorm:"extends"`
		user2.UserInfo      `xorm:"extends"`
		user2.UserEducation `xorm:"extends"`
	}
	var (
		res temp
		has bool
	)
	has, err := lib.X.Table(model.TableUserLogin).Alias("t1").
		Join("INNER", []string{model.TableUserInfo, "t2"}, "t1.id = t2.user_id").
		Join("INNER", []string{model.TableUserEducation, "t3"}, "t1.id = t3.user_id").
		Where("t1.id=?", userID).
		Get(&res)

	if err != nil {
		return nil, false, err
	}
	if !has {
		return &userSdk.UserDetailResp{}, false, nil
	}

	return &userSdk.UserDetailResp{
		Id:                res.UserLogin.ID,
		Sfid:              strconv.FormatInt(res.UserLogin.SFID.SFID, 10),
		PhoneNumber:       res.UserLogin.PhoneNumber,
		Email:             res.UserLogin.Email,
		PhoneAreaCode:     res.UserLogin.PhoneAreaCode,
		FirstName:         res.UserInfo.FirstName,
		LastName:          res.UserInfo.LastName,
		CurrentUniversity: res.UserEducation.CurrentUniversity,
		Password:          res.UserLogin.Password,
	}, true, nil
}

func (u *UserDao) DetailBySFID(ctx context.Context, userSFID int64) (*userSdk.UserDetailResp, bool, error) {
	type temp struct {
		user2.UserLogin     `xorm:"extends"`
		user2.UserInfo      `xorm:"extends"`
		user2.UserEducation `xorm:"extends"`
	}
	var (
		res temp
		has bool
	)
	has, err := lib.X.Table(model.TableUserLogin).Alias("t1").
		Join("INNER", []string{model.TableUserInfo, "t2"}, "t1.id = t2.user_id").
		Join("INNER", []string{model.TableUserEducation, "t3"}, "t1.id = t3.user_id").
		Where("t1.sfid=?", userSFID).
		Get(&res)

	if err != nil {
		return nil, false, err
	}
	if !has {
		return &userSdk.UserDetailResp{}, false, nil
	}

	return &userSdk.UserDetailResp{
		Id:                res.UserLogin.ID,
		Sfid:              strconv.FormatInt(res.UserLogin.SFID.SFID, 10),
		PhoneNumber:       res.UserLogin.PhoneNumber,
		Email:             res.UserLogin.Email,
		PhoneAreaCode:     res.UserLogin.PhoneAreaCode,
		FirstName:         res.UserInfo.FirstName,
		LastName:          res.UserInfo.LastName,
		CurrentUniversity: res.UserEducation.CurrentUniversity,
		Password:          res.UserLogin.Password,
	}, true, nil
}
